package com.sxz.mall.order.service.impl;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.sxz.mall.common.constant.OrderConstant;
import com.sxz.mall.common.exception.NoStockException;
import com.sxz.mall.common.utils.R;
import com.sxz.mall.common.vo.MemberVO;
import com.sxz.mall.order.dto.OrderCreateTO;
import com.sxz.mall.order.entity.OrderItemEntity;
import com.sxz.mall.order.feign.CartFeignService;
import com.sxz.mall.order.feign.ProductService;
import com.sxz.mall.order.feign.WareFeignService;
import com.sxz.mall.order.interceptor.AuthInterceptor;
import com.sxz.mall.order.service.OrderItemService;
import com.sxz.mall.order.utils.OrderMsgProducer;
import com.sxz.mall.order.vo.*;
//import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sxz.mall.common.utils.PageUtils;
import com.sxz.mall.common.utils.Query;

import com.sxz.mall.order.dao.OrderDao;
import com.sxz.mall.order.entity.OrderEntity;
import com.sxz.mall.order.service.OrderService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Autowired
    CartFeignService cartFeignService;

    @Autowired
    ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    private OrderService orderService;

    @Autowired
    private OrderItemService orderItemService;

    @Autowired
    WareFeignService wareFeignService;

    @Autowired
    ProductService productService;

    @Autowired
    OrderMsgProducer orderMsgProducer;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 使用异步编排
     *
     * @return
     */
    @Override
    public OrderConfirmVo confirmOrder() {
        // 获取当前用户信息，会员, 登录验证成功时就绑定到了ThreadLocal
        MemberVO memberVO = AuthInterceptor.threadLocal.get();

        OrderConfirmVo confirmVo = new OrderConfirmVo();
        System.out.println("主线程:" + Thread.currentThread().getName());
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            // 1、会员地址信息
            System.out.println("子线程:获取会员信息" + Thread.currentThread().getName());
            RequestContextHolder.setRequestAttributes(requestAttributes);
            confirmVo.setAddress(null); // 为空，需要处理UI
        }, threadPoolExecutor);

        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            // 2、商品信息，购物车的信息  存在于redis中的
            System.out.println("子线程:获取购物车信息" + Thread.currentThread().getName());
            RequestContextHolder.setRequestAttributes(requestAttributes);

            List<OrderItemVo> items = cartFeignService.getUserCartItems();
            confirmVo.setItems(items);
        }, threadPoolExecutor);

//        CompletableFuture<Void> future = CompletableFuture.allOf(future1, future2);

        try {
            CompletableFuture.allOf(future1, future2).get();
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 3、金额  总价，除开优惠等，confirmVo自动计算

        // 4、生成防重提交订单的token   类似登录校验  存入redis，绑定到vo
        String token = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 10);
        redisTemplate.opsForValue().set
                (OrderConstant.ORDER_TOKEN_PREFIX + memberVO.getId(), token);

        confirmVo.setOrderToken(token);


        return confirmVo;
    }

    private Lock lock = new ReentrantLock();

    // @GlobalTransactional // seata管理分布式事务
    @Transactional
    @Override
    public OrderResponseVO submitOrder(OrderSubmitVO vo) throws NoStockException{

        OrderResponseVO responseVO = new OrderResponseVO();

        // 1、获取用户信息，验证对应的token
        MemberVO memberVO = AuthInterceptor.threadLocal.get();
        String key = OrderConstant.ORDER_TOKEN_PREFIX + memberVO.getId();
        String token = redisTemplate.opsForValue().get(key);

        // 脚本保证查找和删除是原子操作
        String script = "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";

        Long result = redisTemplate.execute(new DefaultRedisScript<Long>(
                script, Long.class), Arrays.asList(key), vo.getOrderToken());
        if (result == 0) { // 验证失败，重复提交
            responseVO.setCode(1);
            return responseVO;
        }

        OrderCreateTO createTO = createOrder(vo);
        responseVO.setOrderEntity(createTO.getOrderEntity());
        // 1、保存信息
        saveOrder(createTO);

        // 2、锁定库存 feign
        lockWareSpu(createTO, responseVO);

        System.out.println("仓库锁定成功,即将向消息队列发送30s后关单....");

        // 3、会员积分扣除,  出现异常，需要使用seata将上面的操作进行回滚
//        int i = 10 / 0;

        // 延迟 30分钟后取消订单，  模拟是30s
        orderMsgProducer.sendOrderMsg(createTO.getOrderEntity().getOrderSn());

        // 以上获取，下面校验执行存在并发   需要保证token的查询和删除是原子操作
//        try {
//            lock.lock();
//            if (token != null && token.equals(vo.getOrderToken())) {
//                // 第一次提交，应该成功, 需要删除key
//                redisTemplate.delete(key);
//                responseVO.setCode(0);
//
//            } else {
//                // 重复提交
//                responseVO.setCode(1);
//            }
//        } finally {
//            lock.unlock();
//        }
        return responseVO;
    }

    @Override
    public PayVo getOrderPay(String orderSN) {
        PayVo payVo = new PayVo();
        OrderEntity orderEntity = this.baseMapper.selectOne(new QueryWrapper<OrderEntity>().
                eq("order_sn", orderSN));

        payVo.setOut_trader_no(orderSN);
        payVo.setTotal_amount(orderEntity.getTotalAmount().
                setScale(2, RoundingMode.UP).toString());
        payVo.setSubject("支付主题描述：我要支付测试订单");
        payVo.setBody("支付的描述信息，测试手机支付描述");

        return payVo;
    }

    private void lockWareSpu(OrderCreateTO createTO, OrderResponseVO responseVO) throws NoStockException {
        WareSkuLockVO wareSkuLockVO = new WareSkuLockVO();
        wareSkuLockVO.setOrderSN(createTO.getOrderEntity().getOrderSn());
        List<OrderItemVo> itemVos = createTO.getOrderItemEntitys().stream().map((item) -> {
            OrderItemVo orderItemVo = new OrderItemVo();
            orderItemVo.setSkuId(item.getSkuId());
            orderItemVo.setTitle(item.getSkuName());
            orderItemVo.setCount(item.getSkuQuantity());

            return orderItemVo;
        }).collect(Collectors.toList());

        wareSkuLockVO.setItems(itemVos);

        // 远程锁库存
        R r = wareFeignService.orderLockStock(wareSkuLockVO);
        System.out.println("锁库存结果:" + r.getCode());
        if (r.getCode() == 0) {// 锁定成功
            responseVO.setCode(0);
        } else {// 锁定失败
            responseVO.setCode(2); // 库存不足
            throw new NoStockException(10000l);
        }
    }

    private void saveOrder(OrderCreateTO createTO) {
        orderService.save(createTO.getOrderEntity());

        orderItemService.saveBatch(createTO.getOrderItemEntitys());
    }

    private OrderCreateTO createOrder(OrderSubmitVO vo) {
        // 订单   和    订单item
        OrderCreateTO createTO = new OrderCreateTO();

        OrderEntity orderEntity = getOrder();


        // 订单详情Item列表
        List<OrderItemEntity> orderItemList = getOrderItems(orderEntity.getOrderSn());
        createTO.setOrderItemEntitys(orderItemList);

        BigDecimal total_Price = new BigDecimal(0);
        for (OrderItemEntity orderItemEntity : orderItemList) {
            total_Price.add(orderItemEntity.getSkuPrice().
                    multiply(new BigDecimal(orderItemEntity.getSkuQuantity())));
        }

//        orderEntity.setPayAmount(total_Price);
        orderEntity.setTotalAmount(total_Price);
        createTO.setOrderEntity(orderEntity);

        return createTO;
    }

    private List<OrderItemEntity> getOrderItems(String orderSn) {
        List<OrderItemEntity> list = new ArrayList<>();

        // 获取购物车列表
        List<OrderItemVo> orderItemVos = cartFeignService.getUserCartItems();
        if (orderItemVos != null && orderItemVos.size() > 0) {
            // 远程获取spuInfo，通过spuIds  long[]
//            List<Long> spuIds = new ArrayList<>();
            for (OrderItemVo orderItem : orderItemVos) {
//                if (!spuIds.contains(orderItem.getSpuId())) {
//                    spuIds.add(orderItem.getSpuId());
//                }
//            }


//            Long[] spuIdsArray = spuIds.toArray(new Long[spuIds.size()]);
//            List<OrderItemSpuInfoVO> spuInfos = productService.getOrderItemSpuInfoByIds(spuIdsArray);
//            Map<Long, OrderItemSpuInfoVO> map = spuInfos.stream().collect(Collectors.toMap(OrderItemSpuInfoVO::getId, item1 -> item1));

//            for (OrderItemVo orderItem : orderItemVos) {
//                OrderItemSpuInfoVO orderItemSpuInfoVO = map.get(orderItem.getSpuId());
                OrderItemEntity entity = getOrderItem(orderItem);
                // 绑定订单编号
                entity.setOrderSn(orderSn);
                list.add(entity);
            }


        }
        return list;
    }

    private OrderItemEntity getOrderItem(OrderItemVo item) {
        OrderItemEntity orderItemEntity = new OrderItemEntity();

        orderItemEntity.setSkuId(item.getSkuId());
        orderItemEntity.setSkuName(item.getTitle());
        orderItemEntity.setSkuQuantity(item.getCount());
        List<String> skuAttr = item.getSkuAttr();
        String s = StringUtils.collectionToDelimitedString(skuAttr, ";");
        orderItemEntity.setSkuAttrsVals(s);

//        spu信息
//        orderItemEntity.setSpuId(spuInfo.getId());
//        orderItemEntity.setSpuBrand(spuInfo.getBrandName());
//        orderItemEntity.setCategoryId(spuInfo.getCatalogId());
//        orderItemEntity.setSpuPic(spuInfo.getImg());

        // 赠送积分、成长值
        orderItemEntity.setGiftGrowth(item.getPrice().intValue());
        orderItemEntity.setGiftIntegration(item.getPrice().intValue());

        // 设置单价
        orderItemEntity.setSkuPrice(item.getPrice());

        return orderItemEntity;
    }

    private OrderEntity getOrder() {
        OrderEntity orderEntity = new OrderEntity();
        String orderSn = IdWorker.getTimeId();// 订单编号
        orderEntity.setOrderSn(orderSn);
        MemberVO memberVO = AuthInterceptor.threadLocal.get();
        orderEntity.setMemberId(memberVO.getId());
        orderEntity.setMemberUsername(memberVO.getUsername());

        orderEntity.setReceiverCity("眉山");
        orderEntity.setReceiverDetailAddress("花海大道天府大学里");
        orderEntity.setReceiverName("石大哥");
        orderEntity.setReceiverPhone("13679668789");
        orderEntity.setReceiverPostCode("60039");
        orderEntity.setReceiverRegion("视高街道");
        orderEntity.setReceiverProvince("四川");

        // 设置订单状态
        orderEntity.setStatus(OrderConstant.OrderStateEnum.FOR_THE_PAYMENT.getCode());

        return orderEntity;
    }

    @Transactional // 事务A
    public void a(){

        OrderServiceImpl o = (OrderServiceImpl) AopContext.currentProxy();
        o.b(); //事务A
        o.c(); // 事务C, 内部报错，它不会回滚

//        int a = 10/0;
    }

    @Transactional
    public void b(){

    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void c(){

    }

}